package bid

import (
	"encoding/json"
	"fmt"
	"git.apache.org/thrift.git/lib/go/thrift"
	"github.com/garyburd/redigo/redis"
	"lpaiche.com/biddingconsumer/lib/gen-go/Services/AuctionService"
	u "lpaiche.com/utils"
	"strconv"
	"time"
)

var (
	bidQueIng        string              //处理中的队列key
	bidQueComplete   string              //处理完成的队列key
	bidReQue         string              //处理未成功需要重新处理的列队key
	dealingNum       int64               //处理中的条数
	dealingOrderChan map[int64]chan bool //处理中的channel标识
)

func GoStart(cfgPath string) {
	dealingNum = 0
	dealingOrderChan = make(map[int64]chan bool)

	u.InitConfig(cfgPath)
	fmt.Println(u.GetConfig())
	conf := u.GetConfig()

	bidQue := conf.Hammer.BidQue
	if bidQue == "" {
		msg := "配置conf.Hammer.BidQue不正确!"
		fmt.Println(msg)
		u.Panic(msg)
	}
	bidReQue = bidQue + "::re"
	bidQueIng = bidQue + "::ing"
	bidQueComplete = bidQue + "::com"

	go goCleanQue()
	dealFailedQue()

	rp := u.NewRedisPoolFromConfig()
	defer rp.Close()

	for {
		bidMsgJsonStr, err := redis.String(rp.Do("BRPOPLPUSH", bidQue, bidQueIng, 0))
		if err != nil {
			u.Trace(err)
			time.Sleep(5000000 * time.Microsecond)
		}
		if len(bidMsgJsonStr) > 0 {
			go goBiddingDeal(bidMsgJsonStr)
			continue
		} else {
			time.Sleep(500 * time.Microsecond)
		}
	}
}

//处理失败的出价消息
func dealFailedQue() {
	rp := u.NewRedisPoolFromConfig()
	defer rp.Close()

	for {
		r, err := redis.String(rp.Do("RPOPLPUSH", bidQueIng, bidReQue))
		if err != nil {
			u.Trace(err)
		}
		if len(r) > 0 {
			continue
		}
		break
	}

	for {
		bidMsgJsonStr, err := redis.String(rp.Do("RPOPLPUSH", bidReQue, bidQueIng))
		if err != nil {
			u.Trace(err)
		}
		if len(bidMsgJsonStr) > 0 {
			u.Trace("重新处理队列出价:" + bidMsgJsonStr)
			go goBiddingDeal(bidMsgJsonStr)
			continue
		}
		break
	}

}

//整理处理完毕的队列
func goCleanQue() {
	rp := u.NewRedisPoolFromConfig()
	defer rp.Close()

	for {
		if time.Now().Unix()%86400 == 0 {
			dealingOrderChan = make(map[int64]chan bool)
		}

		bidMsgJsonStr, err := redis.String(rp.Do("LINDEX", bidQueIng, -1))
		if err != nil {
			u.Trace(err)
			time.Sleep(5000000 * time.Microsecond)
		}
		if len(bidMsgJsonStr) > 0 {
			biddingMsg := JsonStr2BiddingMsg(bidMsgJsonStr)
			field := getFiledId(biddingMsg)
			r, err := redis.Int64(rp.Do("HDEL", bidQueComplete, field))
			if err != nil {
				u.Trace(err)
			}
			fmt.Println(field)
			fmt.Println(r)
			if r > 0 {
				dealingNum--
				u.Trace("清理队列出价:" + field + ", 处理中还有：" + strconv.FormatInt(dealingNum, 10))
				rp.Do("RPOP", bidQueIng)
				continue
			} else {
				u.Trace("处理中队列未发现需要清理的内容,处理中还有：" + strconv.FormatInt(dealingNum, 10))
				time.Sleep(time.Second * 2)
			}
		}
	}
}

//启动处理
func goBiddingDeal(biddingMsgJsonStr string) {
	dealingNum++
	biddingMsg := JsonStr2BiddingMsg(biddingMsgJsonStr)

	if dealingOrderChan[biddingMsg.OrderId] == nil {
		dealingOrderChan[biddingMsg.OrderId] = make(chan bool, 1)
	}

	dealingOrderChan[biddingMsg.OrderId] <- true
	go goSendBiddingDeal(biddingMsg)
}

//发送给weaver处理
func goSendBiddingDeal(biddingMsg *AuctionService.BiddingMsg) {

	rp := u.NewRedisPoolFromConfig()
	defer rp.Close()
	now := time.Now()
	field := getFiledId(biddingMsg)
	u.Trace("发起处理出价:---------------------------------" + field + "------------------------------" + now.Format("2006-01-02 03:04:05 PM"))

	conf := u.GetConfig()

	client := getThriftClient(conf.Thrift.Biddinghost)
	//调用应用示例
	r, err := client.BiddingDeal(biddingMsg)
	isSuccess := true
	if err != nil {
		u.Trace("请求错误：" + time.Now().Format("2006-01-02 03:04:05 PM"))
		u.Trace(err)
		isSuccess = false
	}
	//todo 处理结果
	u.Trace(r)
	client.Transport.Close()

	if isSuccess == true {
		//处理成功
		u.Trace("出价消费成功:" + field)
		rp.Do("HSET", bidQueComplete, field, 1)
	}
	<-dealingOrderChan[biddingMsg.OrderId]
	u.Trace("处理请求结束：---------------------------------" + field + "-----------------------------" + time.Now().Format("2006-01-02 03:04:05 PM"))

}

func getFiledId(biddingMsg *AuctionService.BiddingMsg) (field string) {
	field = strconv.FormatInt(biddingMsg.DealerId, 10) + "_" + strconv.FormatInt(biddingMsg.OrderId, 10) + "_" + strconv.FormatInt(biddingMsg.BiddingTime, 10)
	return field
}

//thrift client
func getThriftClient(thriftHostURL string) (client *AuctionService.AuctionServiceClient) {
	http, err := thrift.NewTHttpPostClient(thriftHostURL)
	if err != nil {
		u.Trace("Error thrift 18 opening http failed: %v \n")
		u.Trace(err)
		return
	} else {
		// 数据传输方式
		transport := thrift.NewTBufferedTransport(http, 24*1024*1024)
		// 数据格式
		var protocol thrift.TProtocol = thrift.NewTBinaryProtocolTransport(transport)
		protocol = thrift.NewTMultiplexedProtocol(protocol, "AuctionService")
		client = AuctionService.NewAuctionServiceClientProtocol(transport, protocol, protocol)
		err := transport.Open()
		if err != nil {
			u.Trace("Error thrift 25 opening transport failed: %v \n")
			u.Trace(err)
		}
	}
	return client
}

func JsonStr2BiddingMsg(str string) (bidmsg *AuctionService.BiddingMsg) {
	jsonBlob := []byte(str)
	err := json.Unmarshal(jsonBlob, &bidmsg)
	if err != nil {
		u.Trace(err)
	}
	// fmt.Println(bidmsg)
	return bidmsg
}
